/*
 *
 *  Copyright (C) 2010 Tal Eisenberg
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package gui;

import java.awt.Color;
import java.awt.Font;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import tal.drivechain.chain.AbortChainException;
import tal.drivechain.gui.GUIModule;
import tal.drivechain.gui.GUITextBox;
import tal.drivechain.matchers.VarMatcher;
import tal.drivechain.plugin.Channel;
import tal.drivechain.variable.types.DataType;
import tal.drivechain.variable.SetProperty.Flag;
import tal.drivechain.variable.VarTableAction;
import tal.drivechain.variable.Variable;

/**
 *
 * @author Main
 */
public class TextBox extends GUIModule implements DocumentListener {
    private GUITextBox text = new GUITextBox();
    private Variable onRelease;
    private VarMatcher releaseTrigger, updateTrigger;
    private boolean releaseOnChange, sendOnRelease;
    private Variable currentText;
    private VarTableAction setCurrentText;
    
    @Override
    public void setupProperties() throws IllegalArgumentException, AbortChainException {
        UIManager.put("ScrollBar.width", new Integer(8));

        setRows((Integer)props.getProperty("rows"));
        component = text;
        text.initTextComponent();

        super.setupProperties();

        currentText = new Variable("text", DataType.STRING, "", true);
        setCurrentText = new VarTableAction("text", VarTableAction.Action.SET_ANY);
    }

    public void setColumns(Integer value) {
        text.setColumns(value);
    } public int getColumns() { return text.getColumns(); }

    public void setRows(Integer value) {
        text.setRows(value);
    } public int getRows() { return text.getRows(); }
    
    public void setText(String value) {
        text.setText(value);
    } public String getText() { return text.getText(); }

    @Override
    public void setEnabled(Boolean value) {
        super.setEnabled(value);
        text.setEnabled(enabled);
    }

    @Override
    public void setNegative(Boolean value) {
        super.setNegative(value);
        text.setNegative(negative);
    }

    @Override
    public void setFont(Font value) {
        super.setFont(value);
        text.setFont(font);
    }

    @Override
    public void setColor(Color value) {
        super.setColor(value);
        text.setColor(color);
    }


    public void setWordWrap(Boolean value) {
        text.setWordWrap(value);
    } public Object getWordWrap() {
        return text.getWordWrap();
    }

    public void setTabSize(Integer value) {
        text.setTabSize(value);
    } public int getTabSize() {
        return text.getTabSize();
    }

    public void setEditable(Boolean value, Flag flag) {
        text.setEditable(value);
    } public boolean getEditable() { return text.isEditable(); }

    public void setReleaseTrigger(VarMatcher value) {
        releaseTrigger = value;
    } public VarMatcher getReleaseTrigger() { return releaseTrigger; }

    public void setUpdateTrigger(VarMatcher value) {
        updateTrigger = value;
    } public VarMatcher getUpdateTrigger() { return updateTrigger; }

    public void setReleaseOnKey(KeyStroke value) {
        if (value==null && keylistener!=null) {
            text.removeKeyListener(keylistener);
            keylistener = null;
        } else if (value!=null) {
            if (keylistener!=null)
                text.removeKeyListener(keylistener);
            keylistener = new ReleaseKeyListener(value);
            text.addKeyListener(keylistener);
        }
    } public KeyStroke getReleaseOnKey() { if (keylistener==null) return null; else return keylistener.key; }

    class ReleaseKeyListener extends KeyAdapter {
        KeyStroke key;

        public ReleaseKeyListener(KeyStroke keycode) { this.key = keycode; }

        @Override
        public void keyPressed(KeyEvent e) {
            KeyStroke stroke = KeyStroke.getKeyStroke(e.getKeyCode(), e.getModifiers());
            if (stroke.getModifiers()==key.getModifiers() && stroke.getKeyCode()==key.getKeyCode())
                release();
        }
    } private ReleaseKeyListener keylistener = null;

    public void setReleaseOnChange(Boolean value, Flag flag) {
        releaseOnChange = value;
    } public boolean getReleaseOnChange() { return releaseOnChange; }

    public void setOnRelease(Variable value) {
        if (value==null) sendOnRelease = false;
        else {
            sendOnRelease = true;
            onRelease = value;
        }
    } public Variable getOnRelease() { return onRelease; }

    @Override
    protected void msgReceived(Variable in, long timestamp, Channel channel) {
        if (releaseTrigger.matches(in, channel, this)) {
            setInVars(in, timestamp, channel);
            release();
        } else if (updateTrigger.matches(in, channel, this)) {
            setInVars(in, timestamp, channel);
            Object val = in.getValue(this);
            if (val==null) return;
            
            String stext = val.toString();
            //set caret on last line.
            text.setText(stext);
            int lastline = stext.lastIndexOf("\n")+1;
            if (lastline>=stext.length()) lastline = stext.length()-1;
            if (lastline<0) lastline = 0;
            text.getTextComponent().setCaretPosition(lastline);
        }
    }

    public void insertUpdate(DocumentEvent e) {
        if (releaseOnChange) release();
    }

    public void removeUpdate(DocumentEvent e) {
        if (releaseOnChange) release();
    }

    private void release() {
        if (!sendOnRelease) return;
        currentText.setValue(text.getText(), true);
        setCurrentText.set(currentText, localVars, this);
        sendToOutputs(onRelease, -1);
    }

    public void changedUpdate(DocumentEvent e) { }

}
